/*
 *
 *  * Copyright (c) 2016. For Intelligent Group.
 *
 */

package com.intelligent.ispc.client.utils.validation;

import org.jdesktop.beansbinding.ELProperty;
import org.jdesktop.beansbinding.PropertyStateEvent;
import org.jdesktop.beansbinding.PropertyStateListener;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.AbstractLayerUI;

import javax.swing.*;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Iterator;
import java.util.Set;


/**
 * Created by Peter on 2016/8/31.
 */
public class ValidationUI<V extends JComponent> extends AbstractLayerUI<V> {

    private Object object;
    private String propertyName;
    private Validator validator;
    private ELProperty elProperty;
    private PropertyStateListener propertyChangeHandler;
    private JXLayer<V> layer;
    private Class<?> group;

    /**
     * Constructor.
     *
     * @param obj          source object.
     * @param propertyName property name.
     */
    public ValidationUI(Object obj, String propertyName) {
        this.object = obj;
        this.propertyName = propertyName;
        propertyChangeHandler = new PropertyChangeHandler();
        validator = Validation.buildDefaultValidatorFactory().getValidator();

        elProperty = ELProperty.create("${" + propertyName + "}");
    }

    @Override
    public void installUI(JComponent c) {
        if (layer != null) {
            throw new IllegalStateException(getClass().getSimpleName() + " can't be shared between multiple layers");
        }
        super.installUI(c);
        layer = (JXLayer<V>) c;
        elProperty.addPropertyStateListener(object, propertyChangeHandler);

        validate();
    }

    @Override
    public void uninstallUI(JComponent c) {
        super.uninstallUI(c);
        layer = null;
        elProperty.removePropertyStateListener(object, propertyChangeHandler);
    }

    private void validate() {
        Set<ConstraintViolation<Object>> validationMessages;
        if (group == null) {
            validationMessages = validator.validateProperty(object, propertyName);
        } else {
            validationMessages = validator.validateProperty(object, propertyName, group);
        }
        if (validationMessages.size() > 0) {
            Iterator it = validationMessages.iterator();
            if (it.hasNext()) {
                ConstraintViolation cv = (ConstraintViolation) it.next();
                layer.getView().setToolTipText(cv.getMessage());
                return;
            }
        }

        layer.getView().setToolTipText(null);
    }

    @Override
    protected void paintLayer(Graphics2D g2, JXLayer l) {
        super.paintLayer(g2, l);
        if (!isValid()) {
            BufferedImage image = Java2DIconFactory.createErrorIcon();
            g2.drawImage(image, l.getWidth() - image.getWidth() - 1, l.getHeight() - 8, null);
        }
    }

    boolean isValid() {
        return isBlank(layer.getView().getToolTipText());
    }

    /**
     * a copy from the apache common lang.
     * Just use the StringUtils if the common lang jar in your classpath.
     *
     * @param str, blank string.
     */
    private boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    class PropertyChangeHandler implements PropertyStateListener {
        @Override
        public void propertyStateChanged(PropertyStateEvent pse) {
            validate();
            setDirty(true);
        }
    }


    public Class<?> getGroup() {
        return group;
    }

    public void setGroup(Class<?> group) {
        this.group = group;
    }
}
